package com.richinfo.buddy.oauthserver.config;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.RememberMeServices;
import org.springframework.session.FindByIndexNameSessionRepository;
import org.springframework.session.security.SpringSessionBackedSessionRegistry;
import org.springframework.session.security.web.authentication.SpringSessionRememberMeServices;

import com.richinfo.buddy.oauthserver.model.response.JsonVo;
import com.richinfo.buddy.oauthserver.model.response.ResponseCode;
import com.richinfo.buddy.oauthserver.security.CustomAuthenticationDetailsSource;
import com.richinfo.buddy.oauthserver.security.handler.AuthFailureHandler;
import com.richinfo.buddy.oauthserver.security.handler.AuthSuccessHandler;
import com.richinfo.buddy.oauthserver.utils.WebUtils;


/**
 * spring security的配置类
 * 
* Created by WangXJ
* 2019-04-09 14:20
*/
@Configuration
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter{
	
    @Value("${spring.security.sessionManagement.maximumSessions}")
    private Integer maximumSessions;
    
    @Resource
    private FindByIndexNameSessionRepository sessionRepository;

    @Resource
    private AuthSuccessHandler authSuccessHandler;
    
    @Resource
    private AuthFailureHandler authFailureHandler;
    
	@Override
    protected void configure(HttpSecurity http) throws Exception {

		http.csrf().disable();
		http.cors()
				.and()
				.rememberMe()
				.rememberMeServices(springSessionRememberMeServices())
				.and()
				.sessionManagement()
				.maximumSessions(maximumSessions)
                .expiredSessionStrategy(eventØ -> {
                    WebUtils.sendForbiddenError(eventØ.getResponse(), new JsonVo(false, ResponseCode.SESSION_EXPIRED));
                })
				.sessionRegistry(new SpringSessionBackedSessionRegistry(sessionRepository))
				.and()
				.and()
				.exceptionHandling()// 异常处理
                .authenticationEntryPoint((request, response, authException) -> {
                    WebUtils.sendForbiddenError(response, new JsonVo(false, ResponseCode.USER_NOT_LOGIN.getValue(), ResponseCode.USER_NOT_LOGIN.getMessage()));
                })// 处理匿名用户访问无权限资源时的异常
                .accessDeniedHandler((request, response, accessDeniedException) ->
                        WebUtils.sendForbiddenError(response, new JsonVo(false, ResponseCode.USER_NOT_ROLE.getValue(), ResponseCode.USER_NOT_ROLE.getMessage()))
                )// 处理认证过的用户访问无权限资源时的异常
                .and()
                .authorizeRequests()
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/v2/api-docs").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/test").permitAll()
                .anyRequest().authenticated()
                .and()
                .logout()
                .logoutUrl("/logout")
                .logoutSuccessHandler((request, response, authentication) -> {
                    WebUtils.send(response, HttpStatus.OK, new JsonVo(true, "已退出登录"));})
                .and()
                .formLogin()
                .authenticationDetailsSource(authenticationDetailsSource())// 在登录验证时加入额外数据(如验证码);
                .loginProcessingUrl("/login").permitAll()
                .successHandler(authSuccessHandler)
                .failureHandler(authFailureHandler);
	}
	
    // remember-me session方式(重启服务器就失效)
	@Bean
    public RememberMeServices springSessionRememberMeServices() {
  	
        SpringSessionRememberMeServices springSessionRememberMeServices = new SpringSessionRememberMeServices();
        springSessionRememberMeServices.setAlwaysRemember(true);
        springSessionRememberMeServices.setRememberMeParameterName("rememberMe");
      
        return springSessionRememberMeServices;
    }
	
    @Bean
    public CustomAuthenticationDetailsSource authenticationDetailsSource() {
        return new CustomAuthenticationDetailsSource();
    }
}
